package client;

import java.io.BufferedReader;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import security.Channel;
import security.MasterChannel;

/**
 * Thread reading from an InputStream and writing to stdout. If a Users logs in,
 * a UDPListenerThread gets started.
 */
public class TCPListenerThread implements Runnable, Stoppable {

    private static final Logger logger = Logger.getLogger("TCPListenerThread");
    private static final String IN_LOGGED_IN = "!logged-in";
    private static final String OUT_LOGGED_IN = "Successfully logged in as %s!";
    private static final String IN_LOGGED_OUT = "!logged-out";
    private static final String OUT_LOGGED_OUT = "Successfully logged out as %s!";
    private static final String IN_CONFIRMED = "!confirmed";
    private static final String IN_REJECTED = "!rejected";
    private static final String IN_CLIENT_LIST = "!client-list";
    private static final String IN_SERVER_OFF = "!server-off";
    private static final String IN_CLIENT_LIST_HIDDEN = "!hidden-client-list";
    private static final String OUT_CLIENT_LIST = "Active Clients" + System.getProperty("line.separator") + "%s";
    private final MasterChannel masterChannel;
    private BufferedReader bufferedReader;
    private final Client parent;
    
    /*   private int udpPort;
     private UDPListenerThread udpListener;
     private ExecutorService executor=null;*/
    private boolean bStopped = false;

    /**
     * Constructor
     *
     * @param channel Channel, channel the thread is listening for incoming
     * messages;
     * @param parent Stoppable, if the socket/inputstream in gets closed, a stop
     * method on this object shall be called
     */
    public TCPListenerThread(final MasterChannel masterChannel, final Client parent) {
        this.masterChannel = masterChannel;
        this.parent = parent;
        /*       this.udpPort=udpPort;
         executor=Executors.newFixedThreadPool(1);*/
    }

    @Override
    public void run() {
        logger.info("run tcplistener thread");
        try {
            //bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String line = null;
            String output = "";
            while (!bStopped && (line = masterChannel.receiveMessage())!=null) {
                
                logger.log(Level.INFO, "masterChannel receive message {0} ", new Object[]{line});
                if (line != null) {
                    if ((output = processInput(line)).length() > 0) {
                        System.out.println(output);
                    }
                }
            }
            System.out.println("TCPListenerThread loop ended");
        } catch (IOException ioe) {
            System.out.println("IOException occurred while listening for Messages from the Server " + ioe.getMessage());
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            this.stop();
            System.out.println("StreamReaderThread stops...");
        }
    }

    /**
     * Processes the received machine-readable-tcp-message-texts and transforms
     * them to user-readable-texts. If a login happened successfully an
     * UDPListenerThread gets started. If a logout happened successfully the
     * UDPListenerThread gets stopped.
     *
     * @param input String machine-readable-notification-text
     * @return String user-readable-text
     */
    public String processInput(final String input) {
        String strRet = input;
        if (input.startsWith(IN_LOGGED_IN)) {
            final String user = input.substring(IN_LOGGED_IN.length());
            
            /*	   try          //should not be used in example 2
             {
             udpListener=new UDPListenerThread(udpPort,user);
             executor.execute(udpListener);
             }
             catch(SocketException ex)
             {
             System.out.println("UDP-Socket could not be opened, or couldn't be bound to port: "+udpPort+"!");
             }*/
            strRet = String.format(OUT_LOGGED_IN, user);
        } else if (input.startsWith(IN_LOGGED_OUT)) {
            final String user = input.substring(IN_LOGGED_OUT.length());
            /*		   if(udpListener!=null)
             {
             udpListener.stop();
             }*/
            strRet = String.format(OUT_LOGGED_OUT, user);
        } else if (input.startsWith(IN_CONFIRMED) || input.startsWith(IN_REJECTED)) {
            parent.setBlocked(false);
        } else if (input.startsWith(IN_CLIENT_LIST)) {
            final String clients = input.substring(IN_CLIENT_LIST.length());
            parent.updateUsers(clients);
            strRet = String.format(OUT_CLIENT_LIST, clients);
        } else if (input.startsWith(IN_CLIENT_LIST_HIDDEN)) {
            parent.updateUsers(input.substring(IN_CLIENT_LIST_HIDDEN.length()));
            return "";
        }
        return strRet;
    }

    @Override
    public synchronized void stop() {
        if (!bStopped) {
            bStopped = true;
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (IOException e) {
                //ignore
            }
            masterChannel.close();
            /*		   if(udpListener!=null)
             {
             udpListener.stop();
             }
             executor.shutdown();
             executor.shutdownNow();*/
            //parent.stop();
        }
    }
}
